package com.example.common.exception;

import com.example.common.response.ComResponseEnum;
import com.example.common.response.IResponseEnum;
import com.example.common.response.ResponseData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @Author: ChenZhiXiang
 * @Date: 2019/6/16 11:50
 * @Description: 全局异常处理
 */
@ControllerAdvice
@Slf4j
public class MyExceptionHandler {

    @ResponseBody
    @ExceptionHandler(IException.class)
    public Map<String,Object> errorHandler(Exception e){
        Map<String, Object> map = new HashMap<>();
        if (e instanceof IException){
            map.put("code",((IException) e).getCode());
            map.put("msg",e.getMessage());
        } else {
            String message = e.getMessage();
            map.put("code",500);
            map.put("msg",message == null || message.trim().isEmpty() ? "未知错误" : message);
            log.error(message, e);
            e.printStackTrace();
        }
        return map;
    }

    /**
     * 处理参数校验异常
     * @param bindingResult
     * @return
     * @throws Exception
     */
    @ExceptionHandler(value = BindException.class)
    @ResponseBody
    public String bindingResultHandler(BindException be, BindingResult bindingResult) throws Exception {
        log.error("PpValidatorExceptionHandler.handleBindException", be);
        // 得到全部错误
        List<ObjectError> errors = be.getAllErrors();
        StringBuilder stringBuilder = new StringBuilder();
        for (ObjectError error : errors){
            if (stringBuilder.length() != 0){
                stringBuilder.append("，");
            }
            stringBuilder.append(error.getDefaultMessage());
        }
        String msg = stringBuilder.toString();
        return ResponseData.FiledResponse(msg);
    }

    /**
     * 处理参数异常
     * @param e2
     * @return
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public String handleMethodArgumentNotValidException(MethodArgumentNotValidException e2) throws Exception{
        // 获取到所有错误
        List<ObjectError> errors = e2.getBindingResult().getAllErrors();
        StringBuilder stringBuilder = new StringBuilder();
        for (ObjectError error : errors) {
            if (stringBuilder.length() != 0) {
                stringBuilder.append("，");
            }
            stringBuilder.append(error.getDefaultMessage());
        }
        String msg =stringBuilder.toString();
        return ResponseData.FiledResponse(msg);
    }

    /**
     * 参数错误异常处理
     * @param e3
     * @return
     * @throws Exception
     */
    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseBody
    public String handleConstraintViolationException(ConstraintViolationException e3) throws Exception{
        // 获取所有错误信息
        Set<ConstraintViolation<?>> violations = e3.getConstraintViolations();
        StringBuilder stringBuilder = new StringBuilder();
        for (ConstraintViolation<?> violation : violations) {
            if (stringBuilder.length() != 0) {
                stringBuilder.append("，");
            }
            stringBuilder.append(violation.getMessage());
        }
        String msg =stringBuilder.toString();
        return ResponseData.FiledResponse(msg);
    }

    /**
     * 封装业务异常为ResponseData
     *
     * @param e
     * @return
     * @throws Exception
     */
    @ExceptionHandler(value = BusinessException.class)
    @ResponseBody
    public ResponseData businessExceptionHandler(BusinessException e) throws Exception {
        IResponseEnum responseEnum = e.getResponseEnum();
        // 如果没有异常码，则按照不可控异常处理
        if (responseEnum == null) {
            return defaultHandler(e);
        }

        // 自带堆栈，则打印
        if (e.getCause() != null) {
            log.error(e.getMessage(), e);
        }
        return new ResponseData(responseEnum, e.getData());
    }

    /**
     * 处理所有不可控的异常，对调用方屏蔽错误细节
     *
     * @param t
     * @return
     * @throws Exception
     */
    @ExceptionHandler(value = Throwable.class)
    @ResponseBody
    public ResponseData defaultHandler(Throwable t) throws Exception {
        log.error(t.getMessage(), t);
        return ResponseData.FAILURE;
    }

    /**
     * 用户名重复异常捕获
     * @param t
     * @return
     * @throws Exception
     */
    @ExceptionHandler(value = DuplicateKeyException.class)
    @ResponseBody
    public ResponseData SQLIntegrityConstraintViolationException(DuplicateKeyException t) throws Exception {
        log.error(t.getMessage(), t);
        return new ResponseData(ComResponseEnum.USER6);
    }

}
